/**
* @author Meng Zhang
**/

#include "stdafx.h"
#include "TextBufferFactory.h"
#include "TextBuffer.h"
#include "TextBufferView.h"
#include "../MFC/CineApp.h"
#include "TextFile/textfile.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#endif

const TCHAR DEFAULT_TEXT_BUFFER[] = TEXT("SCRATCH");

//IMPLEMENT_SINGLETON(TextBufferFactory)

BufferBase* TextBufferFactory::CreateBuffer( BufferCreateInfo* bufferCreateInfo /*= NULL*/ ) {
	if (bufferCreateInfo==NULL) {
		return cine->EmptyBuffer();
	}

	ASSERT(bufferCreateInfo->createInfo!=NULL);
	
	TCHAR* path = (TCHAR*)bufferCreateInfo->createInfo;
	for (std::set<TextBuffer*>::iterator iter = textBuffers.begin();iter !=textBuffers.end() ; ++iter) {
		if ((*iter)->PathFilename()==path)
			return *iter;
	}
	int docid = scintillaCtrl->GetDocPointer();
	scintillaCtrl->AddRefDocument(docid);
	scintillaCtrl->SetDocPointer(0);

	WriteLog("Doc id %d Created\n",docid);
	TextBuffer* ret = new TextBuffer(docid,(TCHAR*)bufferCreateInfo->createInfo);
	LoadFile(*ret);
	if ((TCHAR*)bufferCreateInfo->createInfo!=DEFAULT_TEXT_BUFFER) {
		//BufferController::Instance()->RegisterBuffer(ret);
		textBuffers.insert(ret);
	}

	return ret;
}

TextBufferFactory::TextBufferFactory() {
	WriteLog("TextBufferFactory Created\n");
	/*if (!scintillaCtrl.Create(WS_CHILD , CRect(0,0,0,0), AfxGetMainWnd()->GetDesktopWindow(), TEXT_BUFFER_FACTORY)) {
		ASSERT(!"Error Create TextBufferFactory!");
	}*/
	cine = ((CCineApp*)AfxGetApp());
	scintillaCtrl = cine->GetScintillaCtrl();
	ASSERT_VALID(scintillaCtrl);
	BufferCreateInfo createInfo;
	memset(&createInfo , 0 , sizeof(createInfo));
	createInfo.createInfo = (UINT_PTR)DEFAULT_TEXT_BUFFER;
	emptyBuffer = (TextBuffer*)CreateBuffer( &createInfo );
	cine->EmptyBuffer(emptyBuffer);
}

void TextBufferFactory::ReleaseBuffer( TextBuffer* buffer ) {
	WriteLog("Doc id %d is released\n",buffer->DocId());
	scintillaCtrl->ReleaseDocument(buffer->DocId());
}

BufferListener* TextBufferFactory::CreateView() {
	return new CTextBufferView;
}

/*void TextBufferFactory::SetBufferContent( int id , const TCHAR* content ,int length) {
	scintillaCtrl->SetDocPointer(id);
	scintillaCtrl->AddText(length , content);
	scintillaCtrl->SetDocPointer(0);
}*/

void TextBufferFactory::LoadFile( TextBuffer& buffer ) {
	scintillaCtrl->SetDocPointer(buffer.DocId());//handle this doc
	scintillaCtrl->Cancel();
	scintillaCtrl->SetUndoCollection(0);
	
	CTextFileRead file(buffer.PathFilename().GetString());
	scintillaCtrl->SetCodePage(SC_CP_UTF8);
	CString content;
	file.Read(content);
	scintillaCtrl->SetText(content.GetString());
	
	scintillaCtrl->SetUndoCollection(1);
	scintillaCtrl->EmptyUndoBuffer();
	scintillaCtrl->SetSavePoint();

	scintillaCtrl->SetDocPointer(0);

	UpdateBufferSwap(buffer);
}

void TextBufferFactory::SaveFile( TextBuffer &buffer ) {
	scintillaCtrl->SetDocPointer(buffer.DocId());

	CTextFileWrite file(buffer.PathFilename().GetString());	

	//need lenghth + 1
	CString content = scintillaCtrl->GetText(scintillaCtrl->GetTextLength()+1);
	
	file.Write(content);

	scintillaCtrl->SetSavePoint();
	scintillaCtrl->SetDocPointer(0);

	UpdateBufferSwap(buffer);
}

bool TextBufferFactory::EnsureSave( TextBuffer &buffer ) {
	if (!buffer.IsDirty())
		return true;

	CString msg = buffer.PathFilename() + TEXT(" Is Modified , want a Save?\n");
	int ret = AfxMessageBox(msg,MB_YESNOCANCEL);
	
	switch (ret) {
				case IDYES:
					SaveFile(buffer);
					break;
				case IDNO:
					RestoreBufferFromSwap(buffer);
					break;
				case IDCANCEL:
					return false;
				default:
					break;
	}

	return true;
}

bool TextBufferFactory::DestroyBuffer( BufferBase* buffer ) {
	std::set<TextBuffer*>::iterator iter = textBuffers.find((TextBuffer*)buffer);
	if (iter==textBuffers.end())
		return false;

	ReleaseBuffer(*iter);
	delete (*iter);
	textBuffers.erase(iter);
	return true;
}

bool TextBufferFactory::EnsureSaveModify() {
	std::set<TextBuffer*>::iterator iter;
	for (iter = textBuffers.begin() ; iter != textBuffers.end() ;) {
		TextBuffer *buffer = (*iter++);
		if (buffer->IsDirty() &&!EnsureSave(*buffer)) {//Got an TextBuffer && isDirty
			return false;
		}
		ClearBufferSwap(*buffer);
	}
	return true;
}

void TextBufferFactory::Destroy() {
	std::set<TextBuffer*>::iterator iter;
	for (iter = textBuffers.begin() ; iter != textBuffers.end() ; ) {
		TextBuffer *buffer = *(iter++);
		ReleaseBuffer(buffer);
		delete buffer;
	}
}

bool TextBufferFactory::HaveBuffer( BufferBase* buffer ) {
	return textBuffers.find((TextBuffer*)buffer)!=textBuffers.end();
}

TextBufferFactory::~TextBufferFactory() {
	WriteLog("TextBufferFactory Destroyed\n");
}

void TextBufferFactory::UpdateBufferSwap( TextBuffer& buffer ) {
	if (buffer.PathFilename()==DEFAULT_TEXT_BUFFER)
		return;
	CString name = buffer.PathFilename() + _T(".swp");
	CopyFile(buffer.PathFilename(),name,FALSE);
}

void TextBufferFactory::RestoreBufferFromSwap( TextBuffer &buffer ) {
	if (buffer.PathFilename()==DEFAULT_TEXT_BUFFER)
		return;
	CString name = buffer.PathFilename() + _T(".swp");
	CopyFile(name,buffer.PathFilename(),FALSE);
}

void TextBufferFactory::ClearBufferSwap( TextBuffer& buffer ) {
	if (buffer.PathFilename()==DEFAULT_TEXT_BUFFER)
		return;
	CString name = buffer.PathFilename() + _T(".swp");
	DeleteFile(name);
}

void TextBufferFactory::VirtualSave( TextBuffer &buffer ) {
	scintillaCtrl->SetDocPointer(buffer.DocId());

	CTextFileWrite file(buffer.PathFilename().GetString());	

	//need lenghth + 1
	CString content = scintillaCtrl->GetText(scintillaCtrl->GetTextLength()+1);

	file.Write(content);
}